package com.xncoding.freemarker.utile;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import org.apache.commons.lang3.RandomUtils;

import java.util.Random;

/**
 * @author cuiyi
 */

public class SnowflakeSequence {

    /** 开始时间截 (2017-05-12) */
    private final long EPOCH = 1494575286033L;

    /** 实例标识所占位数 */
    private final long INSTANCEID_BITS = 5L;

    /** 数据中心标识所占位数 */
    private final long DATACENTERID_BITS = 5L;

    /** 支持的最大实例 31 */
    private final long MAX_INSTANCEID = -1L ^ (-1L << INSTANCEID_BITS);

    /** 支持的最大数据中心标识 31 */
    private final long MAX_DATACENTERID = -1L ^ (-1L << DATACENTERID_BITS);

    /** 序列位数 */
    private final long SEQUENCE_BITS = 12L;

    /** 实例标识 向左移12位 */
    private final long INSTANCEID_SHIFT = SEQUENCE_BITS;

    /** 数据中心标识 向左移17位 */
    private final long DATACENTERID_SHIFT = SEQUENCE_BITS + INSTANCEID_BITS;

    /** 时间截 向左移22位 */
    private final long TIMESTAMP_SHIFT = SEQUENCE_BITS + INSTANCEID_BITS + DATACENTERID_BITS;

    /** 序列掩码 4095 */
    private final long SEQUENCE_MASK = -1L ^ (-1L << SEQUENCE_BITS);


    /** 实例标识(0~31) */
    private long instanceId;

    /** 数据中心标识(0~31) */
    private long datacenterId;

    public long getInstanceId() {
        return instanceId;
    }

    public long getDatacenterId() {
        return datacenterId;
    }

    /** 毫秒内序列(0~4095) */
    private long sequence = 0L;

    /** 基础序列号, 每发生一次时钟回拨即改变, basicSequence += stepSize */
    private long basicSequence = 0L;

    /** 步长, 1024 */
    private static long stepSize = 2 << 9;

    /** 上次生成序列的时间截 */
    private long lastTimestamp = -1L;


    public SnowflakeSequence(long instanceId, long datacenterId) {
        if (instanceId > MAX_INSTANCEID || instanceId < 0) {
            throw new IllegalArgumentException(String.format("instanceId can't be greater than %d or less than 0", MAX_INSTANCEID));
        }
        if (datacenterId > MAX_DATACENTERID || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenterId can't be greater than %d or less than 0", MAX_DATACENTERID));
        }
        this.instanceId = instanceId;
        this.datacenterId = datacenterId;
    }


    public synchronized long nextId() {
        long timestamp = currentTimeMillis();

        //如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过这个时候应当抛出异常
        if (timestamp < lastTimestamp) {
            // 处理系统时钟回拨，回拨时间在1s内就硬等
            if (lastTimestamp - timestamp <= 1000L) {
                timestamp = nextTimeMillis(lastTimestamp);
            } else {
                return handleClockBackwards(timestamp);
//                throw new RuntimeException(
//                        String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
            }
        }

        //如果是同一时间生成的，则进行毫秒内序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & SEQUENCE_MASK;
            //毫秒内序列溢出
            if (sequence == 0) {
                //阻塞到下一个毫秒,获得新的时间戳
                timestamp = nextTimeMillis(lastTimestamp);
            }
        }
        //时间戳改变，毫秒内序列重置
        else {
            sequence = 0L;
        }

        //上次生成ID的时间截
        lastTimestamp = timestamp;


        //移位并通过或运算拼到一起组成64位的ID
        return ((timestamp - EPOCH) << TIMESTAMP_SHIFT)
                | (datacenterId << DATACENTERID_SHIFT)
                | (instanceId << INSTANCEID_SHIFT)
                | sequence;
    }

    /**
     * 阻塞到下一个毫秒，直到获得新的时间戳
     * @param lastTimestamp 上次生成ID的时间截
     * @return 当前时间戳
     */
    protected long nextTimeMillis(long lastTimestamp) {
        long timestamp = currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = currentTimeMillis();
        }
        return timestamp;
    }

    /**
     * 处理时钟回拨
     */
    private long handleClockBackwards(long timestamp) {
        basicSequence += stepSize;
        if (basicSequence == SEQUENCE_MASK + 1) {
            basicSequence = 0;
            timestamp = nextTimeMillis(lastTimestamp);
        }
        sequence = basicSequence;

        lastTimestamp = timestamp;

        return ((timestamp - EPOCH) << TIMESTAMP_SHIFT)
                | (datacenterId << DATACENTERID_SHIFT)
                | (instanceId << INSTANCEID_SHIFT)
                | sequence;
    }

    /**
     * 返回以毫秒为单位的当前时间
     * @return 当前时间(毫秒)
     */
    protected long currentTimeMillis() {
        return System.currentTimeMillis();
    }

    //==============================Test=============================================

    //生成id
    public static long generateId(Long id){
        StringBuilder sb=new StringBuilder(id+"");
        StringBuilder reverse = sb.reverse();//将id翻转：我们发现id很长，且高位很长部分是一样的数
        id=new Long(reverse.toString())/1000;//切去部分长度
        while(id>1999999999){//1999999999以内的10位或9位或8位id;....
            id/=10;
        }
        return id;
    }



    /** 测试 */
    public static void main(String[] args) {
        SnowflakeSequence idWorker = new SnowflakeSequence(0, 0);
        for (int i =0 ; i<100;i++){
            String id = generateId(idWorker.nextId())+"";
            System.out.println(id+":"+id.length());
        }

//        System.out.println(RandomUtil.randomString(9));;
//        System.out.println(RandomUtil.randomLong(9));;
    }
    public  static String maopao(){
        Random random = new Random();
        int[] arr  = random.ints(1000).toArray();//{18,13,50,15,4,17,18};

        int temp  = 0 ;
        for(int i = 0 ;i< arr.length -1; i++){

            for(int j = 0; j<arr.length-1-i; j++){
                if(arr[j]>arr[j+1]){
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }

        }
        return "";
    }

}
